package com.lp.guoguo.filter;

import java.io.IOException;
import java.util.ArrayList;

import com.lp.guoguo.common.BusinessException;
import com.lp.guoguo.common.Result;
import com.lp.guoguo.common.ResultCode;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import com.lp.guoguo.constant.SecurityConstants;
import com.lp.guoguo.util.JwtUtil;

import io.jsonwebtoken.Claims;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import com.fasterxml.jackson.databind.ObjectMapper;

@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    private final JwtUtil jwtUtil;

    public JwtAuthenticationFilter(JwtUtil jwtUtil) {
        this.jwtUtil = jwtUtil;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        String token = getJwtFromRequest(request);

        if (StringUtils.hasText(token)) {
            try {
                // First check if token is expired
                if (jwtUtil.isTokenExpired(token)) {
                    handleTokenError(response, ResultCode.TOKEN_EXPIRED);
                    return;
                }

                // Then validate token and get claims
                Claims claims = jwtUtil.validateTokenAndGetClaims(token);
                String username = claims.getSubject();
                
                if (StringUtils.hasText(username)) {
                    UsernamePasswordAuthenticationToken authentication = 
                        new UsernamePasswordAuthenticationToken(username, null, new ArrayList<>());
                    SecurityContextHolder.getContext().setAuthentication(authentication);
                }
            } catch (BusinessException e) {
                handleTokenError(response, ResultCode.TOKEN_INVALID);
                return;
            } catch (Exception e) {
                handleTokenError(response, ResultCode.TOKEN_ERROR);
                return;
            }
        }

        filterChain.doFilter(request, response);
    }

    private void handleTokenError(HttpServletResponse response, ResultCode resultCode) throws IOException {
        response.setContentType("application/json;charset=UTF-8");
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.getWriter().write(new ObjectMapper().writeValueAsString(
            Result.failed(resultCode)
        ));
    }

    private String getJwtFromRequest(HttpServletRequest request) {
        String bearerToken = request.getHeader(SecurityConstants.JWT.TOKEN_HEADER);
        if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(SecurityConstants.JWT.TOKEN_PREFIX)) {
            return bearerToken.substring(SecurityConstants.JWT.TOKEN_PREFIX.length());
        }
        return null;
    }
} 